package com.acxy.ants.core;

import com.acxy.ants.common.kit.CollectionKit;
import com.acxy.ants.core.annotation.Aop;
import com.acxy.ants.core.annotation.Cache;
import com.acxy.ants.resful.RequestMapping;
import com.acxy.ants.core.annotation.Uop;
import com.alibaba.fastjson.JSON;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author MrShun
 * @version 1.0
 * @Date 2017-05-17
 */
public class LogReporter {

    private static boolean reportAfterInvocation = true;
    private static int maxOutputLengthOfParaValue = 512;
    private static Writer writer = new SystemOutWriter();

    private static final ThreadLocal<SimpleDateFormat> sdf = new ThreadLocal<SimpleDateFormat>() {
        protected SimpleDateFormat initialValue() {
            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        }
    };

    public static void setReportAfterInvocation(boolean reportAfterInvocation) {
        LogReporter.reportAfterInvocation = reportAfterInvocation;
    }

    public static void setMaxOutputLengthOfParaValue(int maxOutputLengthOfParaValue) {
        if (maxOutputLengthOfParaValue < 16) {
            throw new IllegalArgumentException("maxOutputLengthOfParaValue must more than 16");
        }
        LogReporter.maxOutputLengthOfParaValue = maxOutputLengthOfParaValue;
    }

    public static void setWriter(Writer writer) {
        if (writer == null) {
            throw new IllegalArgumentException("writer can not be null");
        }
        LogReporter.writer = writer;
    }

    public static boolean isReportAfterInvocation(HttpServletRequest request) {
        if (reportAfterInvocation) {
            return true;
        } else {
            String contentType = request.getContentType();
            if (contentType != null && contentType.toLowerCase().indexOf("multipart") != -1) {
                return true;
            } else {
                return false;
            }
        }
    }

    /**
     * Report the log
     */
    public static final void action(String target, HttpServletRequest request, RequestMapping mapping) {
        StringBuilder sb = new StringBuilder("\nAnts log report -------- ").append(sdf.get().format(new Date())).append(" ------------------------------\n");
        sb.append("Url         : ").append(request.getMethod()).append(" ").append(target).append("\n");
        Class<?> c = mapping.getObject().getClass();
        sb.append("Controller  : ").append(String.valueOf(c.getName())).append(" (").append(c.getSimpleName()).append(".java:1)").append("\n");
        Method m = mapping.getMethod();
        sb.append("Method      : ").append(String.valueOf(m.getName())).append("\n");
        //TODO 判断是否有上传文件打印出路径
        sb.append("Parameter   : ").append(JSON.toJSON(request.getParameterMap())).append("\n");
        Cache cache = m.getAnnotation(Cache.class);
        if (cache != null)
            sb.append("Cache       : ").append("true -> " + cache.value()).append("\n");
        Aop classAop = c.getAnnotation(Aop.class);
        Aop methodAop = m.getAnnotation(Aop.class);
        Uop methodUop = m.getAnnotation(Uop.class);
        if (classAop != null || methodAop != null) {
            Class[] interceptors = CollectionKit.union(classAop == null ? null : classAop.value(), methodAop == null ? null : methodAop.value());
            if (interceptors != null && interceptors.length > 0) {
                interceptors = CollectionKit.minus(interceptors, methodUop == null ? null : methodUop.value());
                if (interceptors.length > 0) sb.append("Interceptor : ");
            }
            for (int i = 0; i < interceptors.length; i++) {
                if (i != 0) sb.append("              ");
                sb.append(interceptors[i].getName()).append(" (").append(interceptors[i].getSimpleName()).append(".java:1)").append("\n");
            }

        }

        sb.append("---------------------------------------------------------------------------\n");

        try {
            writer.write(sb.toString());
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }

    private static class SystemOutWriter extends Writer {
        public void write(String str) throws IOException {
            System.out.print(str);
        }

        public void write(char[] cbuf, int off, int len) throws IOException {
        }

        public void flush() throws IOException {
        }

        public void close() throws IOException {
        }
    }
}
